//本程序在LCD12864液晶屏显示汉字、字符及图形内容
//头文件:
#include <reg52.h>

/********IO引脚定义***********************************************************/
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_E=P1^2;
sbit PSB =P1^6;    	//PSB脚为12864-12系列的串、并通讯功能切换，我们使用8位并行接口，PSB=1

/********宏定义***********************************************************/
#define LCD_Data P0
#define Busy    0x80 //用于检测LCD状态字中的Busy标识

/********函数声明*************************************************************/
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD,BuysC);
unsigned char ReadDataLCD(void);
unsigned char ReadStatusLCD(void);
void LCDInit(void);
void LCDClear(void);
void LCDFlash(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData);
void DisplayImage (unsigned char code *DData);
void Delay5Ms(void);
void Delay400Ms(void);

/********数据定义*************************************************************/
code unsigned char  uctech[] = {"5 1 单片机实验板"};
code unsigned char  net[] = {"I LOVE YOU"};
code unsigned char  mcu[] = {"优秀单片机的选择"};
code unsigned char  qq[] = {"  QQ: 229983894  "};
code unsigned char tmp[]={//128*64点阵图形数据
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x8F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0xC7,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x01,0xEF,0xFF,0x80,0x02,0x08,0x00,0x88,0x02,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0xFF,0xFF,0x80,0x02,0x08,0x0C,0xC8,0x02,0x00,0x7F,0xE1,0xEF,0xC0,0x01,
0x80,0x00,0xFF,0xFF,0x80,0x02,0x08,0x04,0x08,0x3F,0xE0,0x01,0x81,0x29,0x40,0x01,
0x80,0x00,0xFF,0xFC,0x40,0x0F,0xFF,0x01,0xFE,0x22,0x20,0x03,0x01,0x29,0x40,0x01,
0x80,0x01,0xFF,0xFC,0x20,0x02,0x18,0x10,0x20,0x22,0x20,0x06,0x01,0x29,0x40,0x01,
0x80,0x01,0xFF,0xFC,0x00,0x06,0x18,0x18,0x20,0x3F,0xE0,0x06,0x01,0x29,0x40,0x01,
0x80,0x01,0xFF,0xF8,0x10,0x07,0x2C,0x01,0xFC,0x22,0x20,0xFF,0xF1,0x2F,0xC0,0x01,
0x80,0x01,0xFF,0xFC,0x30,0x0E,0xAE,0x00,0x20,0x22,0x20,0x06,0x01,0x28,0x40,0x01,
0x80,0x03,0xFF,0xFC,0x38,0x0A,0x6A,0x00,0x20,0x22,0x20,0x06,0x01,0xE8,0x00,0x01,
0x80,0x03,0xFF,0xFE,0x18,0x0A,0x49,0x0F,0xFE,0x3F,0xE0,0x06,0x01,0x28,0x00,0x01,
0x80,0x03,0xFF,0xFE,0x18,0x02,0x08,0x08,0x20,0x22,0x00,0x06,0x01,0x08,0x20,0x01,
0x80,0x07,0xFF,0xFF,0x17,0x02,0x08,0x18,0x20,0x02,0x08,0x06,0x00,0x08,0x20,0x01,
0x80,0x07,0xFF,0xBF,0x8F,0x82,0x08,0x10,0x20,0x03,0xF8,0x0C,0x00,0x07,0xE0,0x01,
0x80,0x0F,0xFE,0x03,0xF7,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x0F,0xFC,0x00,0x8A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x07,0xF8,0x00,0x08,0x00,0x00,0x00,0x0C,0x01,0x80,0xE0,0x00,0x00,0x00,0x01,
0x80,0x01,0xF8,0x00,0x20,0x00,0x00,0x00,0x04,0x00,0x81,0x20,0x00,0x00,0x00,0x01,
0x80,0x00,0xF8,0x00,0x20,0x00,0x00,0x00,0x04,0x00,0x81,0x20,0x00,0x00,0x00,0x01,
0x80,0x01,0xF8,0x04,0x80,0x01,0xFF,0xFC,0x04,0xFB,0xBC,0xC0,0x39,0x9F,0x00,0x01,
0x80,0x00,0x5C,0x01,0x00,0x01,0x6B,0x58,0x04,0x54,0x89,0x20,0x42,0x55,0x00,0x01,
0x80,0x00,0x0E,0x05,0x00,0x00,0xA5,0x28,0x04,0x24,0x91,0x20,0x42,0x55,0x00,0x01,
0x80,0x00,0x07,0xE8,0x00,0x00,0xA5,0x29,0x0E,0x43,0xFC,0xC4,0x39,0x95,0x00,0x01,
0x80,0x00,0x0F,0xE0,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x3F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0xFE,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x01,
0x80,0x00,0xFB,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0x00,0x01,
0x80,0x00,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x00,0x01,
0x80,0x00,0xF7,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x01,
0x80,0x00,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x01,
0x80,0x01,0xF7,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x01,
0x80,0x00,0xFF,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xE0,0x00,0x01,
0x80,0x01,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x60,0x00,0x01,
0x80,0x01,0xFF,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x20,0x38,0x01,
0x80,0x01,0xF7,0xB7,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0xFE,0x01,
0x80,0x03,0xFB,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x21,0xFF,0x01,
0x80,0x01,0xFD,0xFF,0xC0,0x00,0x40,0x00,0x00,0x13,0x00,0x00,0x03,0x61,0xFF,0x81,
0x80,0x03,0xFF,0xFA,0xE0,0x00,0x40,0x27,0xF8,0x22,0x00,0x00,0x01,0x83,0xFF,0x81,
0x80,0x07,0xFF,0x7F,0xC0,0x3E,0xFE,0x36,0x48,0x67,0xF0,0x20,0x01,0xC1,0xFF,0x81,
0x80,0x07,0xFB,0xDC,0xC0,0x02,0x86,0x06,0x48,0x6C,0x90,0x20,0x01,0x63,0xFF,0x81,
0x80,0x03,0x7E,0xFF,0xC0,0x12,0x84,0x06,0x48,0xA0,0x80,0x20,0x03,0x3B,0xFF,0x81,
0x80,0x0F,0xDF,0xFE,0x00,0x15,0xA0,0x76,0x48,0x24,0xB0,0x20,0x0E,0x1F,0xFF,0x81,
0x80,0x02,0xB7,0xFE,0x00,0x0C,0x20,0x16,0x48,0x2C,0x98,0x20,0x1F,0x07,0xFF,0xCF,
0x80,0x03,0xFF,0xBE,0x00,0x0C,0x20,0x16,0x48,0x21,0x80,0x20,0x3F,0x07,0xFF,0x87,
0x80,0x0F,0xBF,0xBE,0x00,0x0E,0x30,0x17,0x58,0x02,0x00,0x20,0x3F,0x1F,0xFF,0xC7,
0x80,0x3F,0xDF,0xFE,0x00,0x1A,0x70,0x16,0x50,0x2B,0x20,0x20,0x7E,0x1F,0xFF,0xC7,
0x81,0xFF,0xFF,0xBF,0x80,0x12,0x48,0x10,0x40,0x49,0x10,0x30,0x1E,0x1F,0xFF,0xC7,
0x9F,0xFF,0x3F,0xFF,0xE0,0x30,0x84,0x38,0x00,0x48,0x58,0x00,0x1C,0x1F,0xFF,0xFD,
0xDF,0xFF,0x7F,0xBF,0xF0,0x03,0x02,0x47,0xFC,0x4F,0xC0,0x00,0x3C,0x0F,0xFF,0xF5,
0xFF,0xFC,0xFF,0xF7,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x0F,0xFF,0x81,
0xFF,0xF8,0x7F,0xFB,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x07,0xFE,0x01,
0xBF,0xE8,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x03,0xF8,0x01,
0x9F,0xA0,0xFF,0xFB,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x01,0x60,0x01,
0x80,0x81,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0xFF,0xFD,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x80,0x00,0x3F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

/***********主函数开始********************************************************/
void main(void)
{
 	Delay400Ms(); 	//启动等待，等LCD讲入工作状态
 	LCDInit(); 		//LCD初始化
 	Delay5Ms(); 	//延时片刻(可不要)
 	while(1){
 		LCDClear();
		DisplayImage(tmp);				//显示图形
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		LCDClear();
		DisplayListChar(0,1,uctech);	//显示字库中的中文数字
 		DisplayListChar(0,2,net);		//显示字库中的中文数字
		DisplayListChar(0,3,mcu);		//显示字库中的中文
		DisplayListChar(0,4,qq);		//显示字库中的中文数字
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
		Delay400Ms();
 		LCDFlash();						//闪烁效果
	}
}

/***********写数据********************************************************/
void WriteDataLCD(unsigned char WDLCD)
{
 	ReadStatusLCD(); //检测忙 
 	LCD_RS = 1;
 	LCD_RW = 0;
 	LCD_Data = WDLCD;
 	LCD_E = 1;
 	LCD_E = 1;
 	LCD_E = 1;
 	LCD_E = 0;
}

/***********写指令********************************************************/
void WriteCommandLCD(unsigned char WCLCD,BuysC) //BuysC为0时忽略忙检测
{
 	if (BuysC) ReadStatusLCD(); //根据需要检测忙 
 	LCD_RS = 0;
 	LCD_RW = 0; 
 	LCD_Data = WCLCD;
 	LCD_E = 1; 
 	LCD_E = 1;
 	LCD_E = 1;
 	LCD_E = 0;  
}

/***********读数据********************************************************/
unsigned char ReadDataLCD(void)
{
	unsigned char LCDDA;
 	LCD_RS = 1; 
 	LCD_RW = 1;
 	LCD_E = 1;
 	LCD_E = 1;
	LCDDA=LCD_Data;
 	LCD_E = 0;
 	return(LCDDA);
}

/***********读状态*******************************************************/
unsigned char ReadStatusLCD(void)
{
 	LCD_Data = 0xFF;
 	LCD_RS = 0;
 	LCD_RW = 1;
	LCD_E = 1;
	LCD_E = 1;
 	while (LCD_Data & Busy); //检测忙信号	
 	LCD_E = 0;
 	return(1);
}

/***********初始化********************************************************/
void LCDInit(void)
{
 	WriteCommandLCD(0x30,1); //显示模式设置,开始要求每次检测忙信号
 	WriteCommandLCD(0x01,1); //显示清屏
 	WriteCommandLCD(0x06,1); // 显示光标移动设置
 	WriteCommandLCD(0x0C,1); // 显示开及光标设置
}

/***********清屏********************************************************/	
void LCDClear(void) 
{
 	WriteCommandLCD(0x01,1); //显示清屏
 	WriteCommandLCD(0x34,1); // 显示光标移动设置
 	WriteCommandLCD(0x30,1); // 显示开及光标设置
}

/***********闪烁效果********************************************************/
void LCDFlash(void)
{
 	WriteCommandLCD(0x08,1); //显示清屏
 	Delay400Ms();
 	WriteCommandLCD(0x0c,1); // 显示开及光标设置
 	Delay400Ms();
 	WriteCommandLCD(0x08,1); //显示清屏
 	Delay400Ms();
 	WriteCommandLCD(0x0c,1); // 显示开及光标设置
 	Delay400Ms();
 	WriteCommandLCD(0x08,1); //显示清屏
 	Delay400Ms();
}

/***********按指定位置显示一个字符*******************************************/	
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
	if(Y<1)
 		Y=1;
	if(Y>4)
 		Y=4;
	X &= 0x0F; 			//限制X不能大于16，Y不能大于1
	switch(Y){
	case 1:X|=0X80;break;
	case 2:X|=0X90;break;
	case 3:X|=0X88;break;
	case 4:X|=0X98;break;
	}
	WriteCommandLCD(X, 0); //这里不检测忙信号，发送地址码
	WriteDataLCD(DData);
}

/***********按指定位置显示一串字符*****************************************/
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
	unsigned char ListLength,X2;
	ListLength = 0;
	X2=X;
	if(Y<1)
 		Y=1;
	if(Y>4)
 		Y=4;
 	X &= 0x0F; 				//限制X不能大于16，Y在1-4之内
 	switch(Y){
	case 1:X2|=0X80;break;	//根据行数来选择相应地址
	case 2:X2|=0X90;break;
	case 3:X2|=0X88;break;
	case 4:X2|=0X98;break;
	}
 	WriteCommandLCD(X2, 1); 	//发送地址码
  	while (DData[ListLength]>=0x20){ //若到达字串尾则退出
   		if (X <= 0x0F){ 			//X坐标应小于0xF
     		WriteDataLCD(DData[ListLength]);
    	 	ListLength++;
	 		X++;
	 		Delay5Ms();
    	}
  	}
}

/********输出128*64图形数据************************************************/
void DisplayImage (unsigned char code *DData){
	unsigned char x,y,i;
	unsigned int tmp=0;
	for(i=0;i<9;){						//分两屏，上半屏和下半屏，因为起始地址不同，需要分开
	for(x=0;x<32;x++){					//32行
		WriteCommandLCD(0x34,1);
		WriteCommandLCD((0x80+x),1);	//列地址
		WriteCommandLCD((0x80+i),1);	//行地址，下半屏，即第三行地址0X88
		WriteCommandLCD(0x30,1);		
		for(y=0;y<16;y++)	
			WriteDataLCD(DData[tmp+y]);//读取数据写入LCD
		tmp+=16;		
	}
	i+=8;
	}
	WriteCommandLCD(0x36,1);			//扩充功能设定
	WriteCommandLCD(0x30,1);
}

/***********短延时********************************************************/
void Delay5Ms(void)
{
 	unsigned int TempCyc = 5552;
 	while(TempCyc--);
}

/***********长延时********************************************************/
void Delay400Ms(void)
{
 	unsigned char TempCycA = 5;
 	unsigned int TempCycB;
 	while(TempCycA--){
  		TempCycB=7269;
  		while(TempCycB--);
 	}
}
